package top.frsf.rpc.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import top.frsf.rpc.constants.RpcConstants;
import top.frsf.rpc.protocol.RpcMessage;
import top.frsf.rpc.protocol.head.RpcHeader;
import top.frsf.rpc.protocol.body.RpcReqBody;
import top.frsf.rpc.protocol.body.RpcRespBody;

import java.lang.reflect.Method;

/**
 * RPC 业务调用处理器
 *
 * @author He Kuntao
 * @since 2025/7/7 10:43
 */
@Slf4j
@RequiredArgsConstructor
public class RpcServiceInvokeHandler extends SimpleChannelInboundHandler<RpcMessage<RpcReqBody>> {

    private final ApplicationContext applicationContext;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcMessage<RpcReqBody> msg) throws Exception {
        try {
            RpcReqBody reqBody = msg.getBody();
            Object result = invokeService(reqBody);
            sendResponse(ctx, msg.getHeader(), result, null);
        } catch (Exception ex) {
            sendResponse(ctx, msg.getHeader(), null, ex);
        }
    }

    private Object invokeService(RpcReqBody reqBody) throws Exception {
        Object serviceBean = applicationContext.getBean(reqBody.getServiceInterface());
        Method method = serviceBean.getClass().getMethod(
                reqBody.getMethodName(),
                reqBody.getParameterTypes()
        );
        return method.invoke(serviceBean, reqBody.getParameters());
    }

    private void sendResponse(ChannelHandlerContext ctx,
                              RpcHeader requestHeader,
                              Object result,
                              Exception ex) {
        RpcMessage<RpcRespBody> response = new RpcMessage<>();

        // 构建响应头
        response.setHeader(buildResponseHeader(
                requestHeader,
                ex == null ? RpcConstants.STATUS_OK : RpcConstants.STATUS_INTERNAL_ERROR
        ));

        // 构建响应体
        response.setBody(RpcRespBody.builder()
                .result(result)
                .dataType(result != null ? result.getClass() : null)
                .errorType(ex != null ? ex.getClass().getName() : null)
                .errorMsg(ex != null ? ex.getMessage() : null)
                .build());

        log.info("响应结果: {}", response);
        ctx.writeAndFlush(response);
    }

    private RpcHeader buildResponseHeader(RpcHeader requestHeader, byte status) {
        return RpcHeader.builder()
                .magic(RpcConstants.MAGIC)
                .version(RpcConstants.VERSION)
                .flags(RpcConstants.FLAG_RESPONSE)
                .serialType(RpcConstants.SERIALIZER_JSON)
                .status(status)
                .requestId(requestHeader.getRequestId())
                .build();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("Channel异常", cause);
        ctx.close();
    }
}
